package com.hjk.common.aop.aspect;

import com.hjk.common.aop.annotation.RedisDistributedLock;
import com.hjk.common.utils.aop.AopUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.hjk.common.utils.aop.AopUtils.getAnnotation;

/**
 * 分布式锁切面类
 *
 * @author huangjunkai
 * @version 1.0
 * @date 2020/7/15 9:33
 */
@Aspect
//@Component
public class RedisDistributedLockAspect {

    @Autowired
    private RedissonClient redissonClient;

    private static final Logger log = LoggerFactory.getLogger(RedisDistributedLockAspect.class);

    @Pointcut("@annotation(com.hjk.common.aop.annotation.RedisDistributedLock)")
    private void distributedLock() {
    }

    @Around("distributedLock()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        RedisDistributedLock annotation = getAnnotation(point,RedisDistributedLock.class);

        //获取key
        String lockKey = annotation.lockKey();
        //获取锁自动释放时间,默认10分钟
        long taskLeaseTime = Optional.of(annotation.taskLeaseTime()).filter(f -> f > 0).orElse(10L);
        //获取锁自动释放单位
        TimeUnit timeUnit = annotation.timeUnit();
        //创建锁对象
        RLock lock = redissonClient.getLock(lockKey);
        Object result = null;
        try {
            //获取锁
            boolean tryLock = lock.tryLock(0, taskLeaseTime, timeUnit);
            if (!tryLock) {
                //获取锁失败，结束任务
                log.info("=========【方法结束】{}未能获取锁，结束任务=========", AopUtils.getFullMethodName(point));
                return null;
            }

            try {
                //执行业务
                log.info("===========【方法执行】{}获取到锁,方法开始执行===========", AopUtils.getFullMethodName(point));
                result = point.proceed();
                TimeUnit.SECONDS.sleep(3);

            } finally {
                //释放锁
                //如果该线程还持有该锁，那么释放该锁。如果该线程不持有该锁，说明该线程的锁已到过期时间，自动释放锁
                if (lock.isLocked()) {
                    lock.unlock();
                }
                log.info("============【方法完成】{}锁已经释放!!=============", AopUtils.getFullMethodName(point));
            }
        } catch (InterruptedException e) {
            log.error("【方法异常】{}获取锁异常，原因：{}", AopUtils.getFullMethodName(point), e.getMessage(), e);
        }


        return result;
    }



}
